#pragma once 

#include "nrtypes.h"
#include <functional>
#include <vector>

template<bool> struct CompileTimeChecker {	CompileTimeChecker(...); };
template<> struct CompileTimeChecker<false> {};
#define STATIC_CHECK(expr, msg) \
	{ \
		struct ERROR_##msg {}; \
		(void)sizeof(CompileTimeChecker<(expr)>(new ERROR_##msg())); \
	}


class NullType {};

//The longest by default
template <int size=2> struct integer_datatype_selector { typedef QWORD integer_datatype; };
template <> struct integer_datatype_selector<1> { typedef BYTE integer_datatype; };
template <> struct integer_datatype_selector<2> { typedef WORD integer_datatype; };
template <> struct integer_datatype_selector<3> { typedef DWORD integer_datatype; };
template <> struct integer_datatype_selector<4> { typedef DWORD integer_datatype; };

//base template, not used itself
template<class TGenerator>
struct generator_traits
{
	typedef TGenerator Generator;
	typedef int ControlSequence;
	typedef int State;
	typedef int Configuration;
	typedef std::less<int> ConfigurationComparer;
	typedef std::less<int> StateComparer;
	static State next(TGenerator* gen) { return 0; }
	static void setConfiguration(
		TGenerator* gen,
		const Configuration &c)
	{ 
	}
};

template<class T>
class SimpleIterator
{
public:
	virtual bool moveNext() = 0;
	virtual T current() const = 0;
};

template<class T>
class CollectionIterator : public SimpleIterator<T>
{
public:
	CollectionIterator(const std::vector<T> &collection)
		: _it(collection.begin()), _last(collection.end())
	{ }

	bool moveNext()
	{
		_it++;
		return _it != _last;
	}

	T current() const
	{
		return *_it;
	}

private:
	typename std::vector<T>::const_iterator _it;
	typename std::vector<T>::const_iterator _last;
};

//operators categories: left and right
struct left_operator_tag {};
struct right_operator_tag {};

//template for choosing multiplication order statically
template<class C, class OperatorCategory>
struct RotatableInvoker
{
	BYTE op(const C *obj, BYTE (C::*func)(BYTE, BYTE) const, BYTE a, BYTE b) const
	{
		return (obj->*func)(a, b);
	}
};

template<class C>
struct RotatableInvoker<C, right_operator_tag>
{
	BYTE op(const C *obj, BYTE (C::*func)(BYTE, BYTE) const, BYTE a, BYTE b) const
	{
		return (obj->*func)(b, a);
	}
};

#define WHOLE_CELLS(TCell, count, unitsize) ((count) * (unitsize) / (sizeof(TCell) * 8) )
#define REMINDER_BITS(TCell, count, unitsize) (((count) * (unitsize)) % (sizeof(TCell) * 8))
#define HEAD_BITS(TCell, reminderBits) (sizeof(TCell) * 8 - (reminderBits))
#define TAIL_BITS(TCell, unitsize, reminderBits) ((unitsize) - HEAD_BITS(TCell, reminderBits))
#define CELLS_NEEDED(TCell, count, unitsize) (WHOLE_CELLS(TCell, count, unitsize) + (REMINDER_BITS(TCell, count, unitsize) == 0 ? 0 : 1))
#define MASK(TCell, nbits) ( ~((~TCell(0)) << nbits ) )
#define MASK_WINDOW(TCell, offset, nbits) ( MASK(TCell, nbits) << offset )

//subscripting of unaligned array
template<class TCell, size_t unitsize>
inline typename TCell getUnit(const TCell* v, size_t index)
{
	size_t wholeBbytes = WHOLE_CELLS(TCell, index, unitsize);
	size_t reminderBits = REMINDER_BITS(TCell, index, unitsize);
	TCell res = (v[wholeBbytes] >> reminderBits) & MASK(TCell, unitsize);
	size_t t = HEAD_BITS(TCell, reminderBits);
	if(t < unitsize)
	{
		res |= v[wholeBbytes + 1] & MASK(TCell, unitsize - t);
	}
	return res;
}

//unit setter
template<class TCell, size_t unitsize>
inline void setUnit(TCell* v, size_t index, TCell value)
{
	TCell mask = MASK(TCell, unitsize);
	value &= mask;
	size_t wholeBbytes = WHOLE_CELLS(TCell, index, unitsize);
	size_t reminderBits = REMINDER_BITS(TCell, index, unitsize);
	v[wholeBbytes] = (v[wholeBbytes] ^ (v[wholeBbytes] & MASK_WINDOW(TCell, reminderBits, unitsize))) 
			| (( value & mask) << reminderBits);
	size_t t = HEAD_BITS(TCell, reminderBits);
	if(t < unitsize)
	{
		v[wholeBbytes + 1] = 
			(v[wholeBbytes + 1] ^ (v[wholeBbytes + 1]& (~MASK(TCell, unitsize - t)))) | (value >> t);
	}
}

template<class TCell, size_t unitsize, size_t count>
class ArrayPacker
{
public:
	//unsafe method
	template<class TInputCell>
	void pack(const std::vector<TInputCell> &v, TCell *data)
	{
		for(size_t i = 0; i < v.size(); i++)
		{
			set(data, i, v[i]);
		}
	}
	typename TCell get(const TCell *data, size_t index) const
	{ 
		return getUnit<TCell, unitsize>(data, index);
	}

	void set(TCell *data, size_t index, TCell value)
	{ 
		setUnit<TCell, unitsize>(data, index, value);
	}
};

template<class TCell, size_t count>
class ArrayPacker<TCell, 8, count>
{
public:
	template<class TInputCell>
	void pack(const std::vector<TInputCell> &v, TCell *data)
	{
		std::copy(v.begin(), v.end(), data);
	}
	TCell get(const TCell *data, size_t index) const
	{ 
		return data[index];
	}

	void set(TCell *data, size_t index, TCell value)
	{ 
		data[index] = value;
	}
};